/**
 * Copyright 2024 Florida Institute for Human and Machine Cognition (IHMC)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package us.ihmc.idl;

import us.ihmc.euclid.tools.EuclidCoreTools;

/**
 * Useful functions to work with the datatypes generated by IDL
 *
 * These functions are called from the generated class files.
 *
 * @author Jesper Smith
 */
public class IDLTools
{
   /**
    * Compare two StringBuilder classes char by char
    *
    * @param a First StringBuilder
    * @param b Second StringBuilder
    * @return true if length and all characters are equal
    */
   public static boolean equals(StringBuilder a, StringBuilder b)
   {
      if (a.length() == b.length())
      {
         for (int i = 0; i < a.length(); i++)
         {
            if (a.charAt(i) != b.charAt(i))
            {
               return false;
            }
         }
      }
      else
      {
         return false;
      }

      return true;
   }

   private interface DoubleProvider
   {
      double get(int i);
   }

   public static boolean epsilonEquals(double a, double b, double epsilon)
   {
      return EuclidCoreTools.epsilonEquals(a, b, epsilon);
   }

   public static boolean epsilonEqualsBoolean(boolean a, boolean b, double epsilon)
   {
      return a == b;
   }

   public static boolean epsilonEqualsPrimitive(double a, double b, double epsilon)
   {
      return EuclidCoreTools.epsilonEquals(a, b, epsilon);
   }

   public static boolean epsilonEqualsEnum(Enum a, Enum b, double epsilon)
   {
      if (a == null && b == null)
      {
         return true;
      }
      else if (a == null || b == null)
      {
         return false;
      }
      else
      {
         return EuclidCoreTools.epsilonEquals(a.ordinal(), b.ordinal(), epsilon);
      }
   }

   public static boolean epsilonEqualsStringBuilder(StringBuilder a, StringBuilder b, double epsilon)
   {
      return equals(a, b);
   }

   public static boolean epsilonEqualsStringBuilderSequence(IDLSequence.StringBuilderHolder a, IDLSequence.StringBuilderHolder b, double epsilon)
   {
      if (a.size() != b.size())
         return false;
      else
         for (int i = 0; i < a.size(); i++)
         {
            if (!epsilonEqualsStringBuilder(a.get(i), b.get(i), epsilon))
            {
               return false;
            }
         }
      return true;
   }

   public static boolean epsilonEqualsBooleanSequence(IDLSequence.Boolean a, IDLSequence.Boolean b, double epsilon)
   {
      if (a.size() != b.size())
         return false;
      else
         for (int i = 0; i < a.size(); i++)
         {
            if (!epsilonEqualsBoolean(a.getBoolean(i), b.getBoolean(i), epsilon))
            {
               return false;
            }
         }
      return true;
   }

   public static boolean epsilonEqualsPrimitiveSequence(DoubleProvider providerA, DoubleProvider providerB, IDLSequence a, IDLSequence b, double epsilon)
   {
      if (a.size() != b.size())
         return false;
      else
         for (int i = 0; i < a.size(); i++)
         {
            if (!epsilonEquals(providerA.get(i), providerB.get(i), epsilon))
            {
               return false;
            }
         }
      return true;
   }

   public static boolean epsilonEqualsEnumSequence(IDLSequence.Enum a, IDLSequence.Enum b, double epsilon)
   {
      if (a.size() != b.size())
         return false;
      else
         for (int i = 0; i < a.size(); i++)
         {
            if (!epsilonEqualsEnum(a.get(i), b.get(i), epsilon))
            {
               return false;
            }
         }
      return true;
   }

   public static boolean epsilonEqualsByteSequence(IDLSequence.Byte a, IDLSequence.Byte b, double epsilon)
   {
      return epsilonEqualsPrimitiveSequence(a::get, b::get, a, b, epsilon);
   }

   public static boolean epsilonEqualsCharSequence(IDLSequence.Char a, IDLSequence.Char b, double epsilon)
   {
      return epsilonEqualsPrimitiveSequence(a::get, b::get, a, b, epsilon);
   }

   public static boolean epsilonEqualsShortSequence(IDLSequence.Short a, IDLSequence.Short b, double epsilon)
   {
      return epsilonEqualsPrimitiveSequence(a::get, b::get, a, b, epsilon);
   }

   public static boolean epsilonEqualsIntegerSequence(IDLSequence.Integer a, IDLSequence.Integer b, double epsilon)
   {
      return epsilonEqualsPrimitiveSequence(a::get, b::get, a, b, epsilon);
   }

   public static boolean epsilonEqualsLongSequence(IDLSequence.Long a, IDLSequence.Long b, double epsilon)
   {
      return epsilonEqualsPrimitiveSequence(a::get, b::get, a, b, epsilon);
   }

   public static boolean epsilonEqualsFloatSequence(IDLSequence.Float a, IDLSequence.Float b, double epsilon)
   {
      return epsilonEqualsPrimitiveSequence(a::get, b::get, a, b, epsilon);
   }

   public static boolean epsilonEqualsDoubleSequence(IDLSequence.Double a, IDLSequence.Double b, double epsilon)
   {
      return epsilonEqualsPrimitiveSequence(a::get, b::get, a, b, epsilon);
   }
}
